﻿using AutoMapper;
using Microsoft.Extensions.Logging;
using Quartz;
using Quartz.Impl;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
using XsqTech.SmartOA.Domain.Table;
using XsqTech.SmartOA.Dtos.XSPDto.FormDto;
using XsqTech.SmartOA.Dtos.XSPDto.FromDto;
using XsqTech.SmartOA.EFCore.Respository;
using XsqTech.SmartOA.IRespository;
using XsqTech.SmartOA.IService;
using XsqTech.SmartOA.Service.DTO;
using XsqTech.SmartOA.Service.Tasks;

namespace XsqTech.SmartOA.Service
{
    public class TimingService:ITimingService
    {
        ITimingRespository _baseTiming;
        ITimingLogRespository _baseTimingLog;
        readonly IMapper _mapper;
        readonly IUnitOfWork _unitOfWork;
        private readonly ILogger<MenuService> _logger;
        IScheduler scheduler;
        ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
        public TimingService(ITimingRespository baseTiming, IMapper mapper, IUnitOfWork unitOfWork, ILogger<MenuService> logger, ITimingLogRespository baseTimingLog)
        {
            _baseTiming = baseTiming;
            _mapper = mapper;
            _unitOfWork = unitOfWork;
            _logger = logger;
            _baseTimingLog = baseTimingLog;
        }




        #region 数据库部分
        /// <summary>
        ///  获取全部Job任务信息
        /// </summary>
        /// <param name="index"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public ResponseModel GetTimingList(string? name,int index,int size)
        {
            var list = _baseTiming.Query();
            if (!string.IsNullOrEmpty(name))
            {
                list = list.Where(x => x.JobName.Contains(name));
            }
            int count = list.Count();
            list = list.Skip(index * size - size).Take(size);
            return new ResponseModel
            {
                Code = State.请求成功,
                Message = "查询成功",
                Data = list,
                Count = count,
            };
        }

        /// <summary>
        /// 删除Job任务信息(单删)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ResponseModel DeleteTiming(string id)
        {
            try
            {
                var list = _baseTiming.Query().FirstOrDefault(x => x.Id.ToString().Equals(id));
                if (list == null)
                {
                    return new ResponseModel
                    {
                        Code = State.请求失败,
                        Message = "未查询的到删除数据",
                    };
                }
                else
                {
                    _baseTiming.Delete(list.Id);
                }
                int data = _unitOfWork.SaveChangs();
                if (data > 0)
                {
                    return new ResponseModel
                    {
                        Code = State.请求成功,
                        Message = "删除成功",
                        Count = data,
                    };
                }
                else
                {
                    return new ResponseModel
                    {
                        Code = State.请求失败,
                        Message = "删除失败",
                        Count = data,
                    };
                }
            }
            catch (Exception ex)
            {
                //控制台输出
                Console.WriteLine(ex.Message);
                //写入日志
                _logger.LogError(ex.Message);
                throw;
            };
        }

        /// <summary>
        /// 删除Job任务信息（批删）
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public ResponseModel AllFormDelete(List<TimingDto> dto)
        {
            try
            {
                foreach (var item in dto)
                {
                    var list = _baseTiming.Query().FirstOrDefault(x => x.Id == item.Id);
                    if (list != null)
                    {
                        _baseTiming.Delete(list.Id);
                    }
                    else
                    {
                        return new ResponseModel
                        {
                            Code = State.请求失败,
                            Message = "未查询的到删除数据",
                        };
                    }
                }
                int data = _unitOfWork.SaveChangs();
                if (data > 0)
                {
                    return new ResponseModel
                    {
                        Code = State.请求成功,
                        Message = "删除成功",
                        Count = data,
                    };
                }
                else
                {
                    return new ResponseModel
                    {
                        Code = State.请求失败,
                        Message = "删除失败",
                        Count = data,
                    };
                }
            }
            catch (Exception ex)
            {
                //控制台输出
                Console.WriteLine(ex.Message);
                //写入日志
                _logger.LogError(ex.Message);
                throw;
            };

        }

        /// <summary>
        /// 添加Job任务信息
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public ResponseModel AddTiming(TimingDto dto)
        {
            try
            {
                //判断表单名称是否重复
                var list = _baseTiming.Query().Where(x => x.JobName == dto.JobName);
                if (list.Count() > 0)
                {
                    return new ResponseModel
                    {
                        Code = State.请求失败,
                        Message = "表单名称已从在",
                    };
                }
                var s = _mapper.Map<Timing>(dto);
                _baseTiming.Add(s);
                int data = _unitOfWork.SaveChangs();
                if (data > 0)
                {
                    return new ResponseModel
                    {
                        Code = State.请求成功,
                        Message = "添加成功",
                        Count = data,
                    };
                }
                else
                {
                    return new ResponseModel
                    {
                        Code = State.请求失败,
                        Message = "添加失败",
                        Count = data,
                    };
                }

            }
            catch (Exception ex)
            {
                //控制台输出
                Console.WriteLine(ex.Message);
                //写入日志
                _logger.LogError(ex.Message);
                throw;
            };
        }
        /// <summary>
        /// 反填Job任务信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ResponseModel TimingQueryId(string id)
        {
            var list = _baseTiming.Query().FirstOrDefault(x => x.Id.ToString().Equals(id));
            return new ResponseModel
            {
                Code = State.请求成功,
                Message = "请求成功",
                Data = list,
            };
        }
        /// <summary>
        /// 修改Job任务信息
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public ResponseModel UpdateTiming(TimingDto dto)
        {
            try
            {
                var s = _mapper.Map<Timing>(dto);
                _baseTiming.Update(s);
                int data = _unitOfWork.SaveChangs();
                if (data > 0)
                {
                    return new ResponseModel
                    {
                        Code = State.请求成功,
                        Message = "修改成功",
                        Count = data,
                    };
                }
                else
                {
                    return new ResponseModel
                    {
                        Code = State.请求失败,
                        Message = "修改失败",
                        Count = data,
                    };
                }

            }
            catch (Exception ex)
            {
                //控制台输出
                Console.WriteLine(ex.Message);
                //写入日志
                _logger.LogError(ex.Message);
                throw;
            };
        }
        /// <summary>
        /// 修改状态
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public bool UpdateState(TimingDto dto)
        {
            try
            {
                if (dto.Zt == 0)
                {
                    dto.Zt = 1;
                }
                else
                {
                    dto.Zt = 0;
                }
                var s = _mapper.Map<Timing>(dto);
                _baseTiming.Update(s);
                int data = _unitOfWork.SaveChangs();
                return data > 0;

            }
            catch (Exception ex)
            {
                //控制台输出
                Console.WriteLine(ex.Message);
                //写入日志
                _logger.LogError(ex.Message);
                throw;
            };
        }

        #endregion

        #region  调度器部分
        /// <summary>
        /// 启动Job任务
        /// </summary>
        /// <param name="data">Job信息</param>
        /// <returns></returns>
        public async Task<ResponseModel> StartScheduleJob(TimingDto data)
        {
            JobKey Job = GetJobkeys(data.JobGroup, data.JobName);//JobKey
            scheduler = OnePackageService();
            if (await scheduler.CheckExists(Job))
            {
                return new ResponseModel
                {
                    Code = State.请求失败,
                    Message = "已有重复Job任务",
                    Data = null,
                };//该Job正在运行，直接结束
            }

            //若运行Job中不存在该Job,就接着敲JobDetail和Trigger（时间策略）

            #region   JobDetail
            var types = AppDomain.CurrentDomain.GetAssemblies()
             .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IJob)))).ToList();
            Type tss = types.Where(x => x.FullName == data.RequestUrl).FirstOrDefault(); //用反射获取了第一个相同命名路径的对象（因为结果会是一个集合）

            IJobDetail jobDetail = JobBuilder.Create(tss) //刚才通过反射拿到的给它用上
              .WithIdentity(data.JobName, data.JobGroup)//Job名称，分组名(后面都通过这个来查找)
              .WithDescription(data.Description)//描述
              .Build();
            jobDetail.JobDataMap.Add("JobId", data.Id);//给拦截器用的主键Id
            #endregion

            #region   Trigger
            ITrigger trigger;
            if (data.TriggerType == "Cron")
            {
                trigger = CreateCrontrigger(data);//创建使用Cron来进行的Trigger
            }
            else
            {
                trigger = CreateSimpletrigger(data);//创建使用Simple来进行的Trigger
            }
            #endregion

            await scheduler.ScheduleJob(jobDetail, trigger);//加入
            await scheduler.Start();


            if (UpdateState(data))
            {
                return new ResponseModel
                {
                    Code = State.请求成功,
                    Message = "成功",
                    Data = null,
                };
            }
            else
            {
                return new ResponseModel
                {
                    Code = State.请求失败,
                    Message = "失败",
                    Data = null,
                };
            }

        }

        /// <summary>
        ///暂停Job任务
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ResponseModel> PauseScheduleJob(TimingDto data)
        {
            JobKey Job = GetJobkeys(data.JobGroup, data.JobName);
            try
            {
                scheduler = OnePackageService();
                if (await scheduler.CheckExists(Job))
                {
                    await scheduler.PauseJob(Job);// PauseJob暂停任务   
                    if (UpdateState(data))
                    {
                        return new ResponseModel
                        {
                            Code = State.请求成功,
                            Message = "处理成功",
                            Data = null,
                        };
                    }
                    else
                    {
                        return new ResponseModel
                        {
                            Code = State.请求失败,
                            Message = "失败",
                            Data = null,
                        };
                    }
                }
                else
                {
                    return (new ResponseModel { Code = State.请求失败, Message = "当前任务不存在或已结束" });
                }
            }
            catch (Exception)
            {
                return new ResponseModel
                {
                    Code = State.请求失败,
                    Message = "失败",
                    Data = null,
                };
                throw;
            }

        }

        #endregion

        #region 调度器快捷夹
        /// <summary>
        /// 生成JobKey（需要分区名称和Job名称）
        /// </summary>
        /// <param name="GroupName"></param>
        /// <param name="JObName"></param>
        /// <returns></returns>
        public JobKey GetJobkeys(string GroupName, string JObName)
        {
            JobKey Job = new JobKey(JObName, GroupName);
            return Job;
        }

        /// <summary>
        /// 创建Cron_Trigger
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public ITrigger CreateCrontrigger(TimingDto data)
        {
            //if (DateTime.Now > data.EndTime)
            //{
            //    data.BeginTime = DateTime.Now;
            //}
            ITrigger triggered = TriggerBuilder.Create()
                 .WithIdentity(data.JobName, data.JobGroup)
                 // .StartAt(data.BeginTime)//从指定时间开始执行
                 //.EndAt(data.EndTime)//指定时间结束
                 .WithCronSchedule(data.Cron)
                 .Build();
            return triggered;
        }

        /// <summary>
        /// 创建Simple_Trigger
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public ITrigger CreateSimpletrigger(TimingDto data)
        {
            ITrigger trigger = TriggerBuilder.Create()
                  .WithIdentity(data.JobName, data.JobGroup)
                    // .StartNow()//启动时立马执行一次，不占用执行次数
                    // .StartAt(data.BeginTime)//从指定时间开始执行
                    .WithSimpleSchedule(w =>
                    {
                        if (data.Yun)
                        {
                            w.WithIntervalInSeconds((int)data.IntervalSecond).RepeatForever();//一直按照Simple间执行
                            //x秒执行一次/一直启用
                        }
                        else
                        {
                            w.WithIntervalInSeconds((int)data.IntervalSecond).WithRepeatCount((int)data.RumTimes);//到了Simple次数后自动结束
                                                                                                                  //x秒执行一次/一共只会执行x次
                        }
                    })
                 .Build();
            return trigger;
        }

        /// <summary>
        /// 一条龙服务（对scheduler的配置）
        /// </summary>
        /// <returns></returns>
        public IScheduler OnePackageService()
        {
            scheduler = schedulerFactory.GetScheduler().Result;
            //   scheduler.ListenerManager.AddJobListener(new JobMonitor(timingRepository));//Job监听器
            //   scheduler.ListenerManager.AddTriggerListener();//Trigger监听器
            scheduler.ListenerManager.AddSchedulerListener(new SchedulerMonitor(_baseTiming,_baseTimingLog,_unitOfWork));//SchedulerJob监听器

            return scheduler;
        }

        #endregion

        #region  反射
        /// <summary>
        /// 反射拿取全部继承了IJob接口的命名路由
        /// </summary>
        /// <returns></returns>
        List<dynamic> ITimingService.After()
        {
            List<dynamic> data = new List<dynamic>();
            var types = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IJob)))).ToList();
            types.ForEach(x =>
            {
                data.Add(new
                {
                    Namespace = x.FullName,
                    Name = x.Name,
                    value = x.FullName,
                });
            });
            return data;
        }

        #endregion
    }
}
